package org.dromara.exam.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.exam.domain.entity.ExamTag;
import org.dromara.exam.domain.bo.ExamTagBo;
import org.dromara.exam.domain.entity.ExamTagRel;
import org.dromara.exam.domain.vo.ExamTagVo;
import org.dromara.exam.enums.TagTypeEnum;
import org.dromara.exam.mapper.ExamTagMapper;
import org.dromara.exam.mapper.ExamTagRelMapper;
import org.dromara.exam.service.IExamTagRelService;
import org.dromara.exam.service.IExamTagService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 标签类型Service业务层处理
 *
 * @author xiyin321
 * @date 2024-04-17
 */
@RequiredArgsConstructor
@Service
public class ExamTagServiceImpl implements IExamTagService {

    private final ExamTagMapper baseMapper;
    private final ExamTagRelMapper tagRelMapper;
    private final IExamTagRelService tagRelService;

    /**
     * 查询标签类型
     */
    @Override
    public ExamTagVo queryById(Long tagId) {
        return baseMapper.selectVoById(tagId);
    }

    /**
     * 查询标签分页列表
     */
    @Override
    public TableDataInfo<ExamTagVo> queryPageList(ExamTagBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<ExamTag> lqw = buildLambdaQueryWrapper(bo);
        Page<ExamTagVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询标签类型列表
     */
    @Override
    public List<ExamTagVo> queryList(ExamTagBo bo) {
        Wrapper<ExamTag> lqw = buildQueryWrapper(bo);
        return baseMapper.selectTagVoList(lqw);
    }

    private LambdaQueryWrapper<ExamTag> buildLambdaQueryWrapper(ExamTagBo bo) {
        LambdaQueryWrapper<ExamTag> lqw = Wrappers.lambdaQuery();
        lqw.eq(ObjectUtil.isNotNull(bo.getTagType()), ExamTag::getTagType, bo.getTagType());
        lqw.like(ObjectUtil.isNotNull(bo.getTagName()), ExamTag::getTagName, bo.getTagName());
        return lqw;
    }

    private Wrapper<ExamTag> buildQueryWrapper(ExamTagBo bo) {
        QueryWrapper<ExamTag> wrapper = Wrappers.query();
        wrapper
            .eq(ObjectUtil.isNotNull(bo.getTagType()), "t.tag_type", bo.getTagType())
            .like(ObjectUtil.isNotNull(bo.getTagName()), "t.tag_name", bo.getTagName())
            .groupBy("t.tag_id", "t.tag_name", "t.tag_type")
            .orderByDesc("tag_count");
        return wrapper;
    }

    /**
     * 新增标签类型
     */
    @Override
    public Boolean insertByBo(ExamTagBo bo) {
        ExamTag add = MapstructUtils.convert(bo, ExamTag.class);
        validEntityBeforeSave();
        return baseMapper.insert(add) > 0;
    }

    /**
     * 修改标签类型
     */
    @Override
    public Boolean updateByBo(ExamTagBo bo) {
        ExamTag update = MapstructUtils.convert(bo, ExamTag.class);
        validEntityBeforeSave();
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave() {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除标签
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> tagIds, Boolean isValid) {
        if (isValid) {
            //删除标签前，将标签数据进行删除
            tagRelService.batchDeleteByTagIds(tagIds);
        }
        return baseMapper.deleteByIds(tagIds) > 0;
    }

    /**
     * 校验标签是否存在
     *
     * @param tagType 标签类型 tagName标签名称
     * @return 存在返回true；不存在返回false
     */
    @Override
    public Boolean checkTagTypeUnique(TagTypeEnum tagType, String tagName) {
        QueryWrapper<ExamTag> wrapper = Wrappers.query();
        // 构建查询条件，标签类型和标签名称判断
        wrapper
            .eq(ObjectUtil.isNotNull(tagType), "tag_type", tagType)
            .eq(ObjectUtil.isNotNull(tagName), "tag_name", tagName);
        ExamTag tag = baseMapper.selectOne(wrapper);
        return tag != null;
    }

    /**
     * 批量处理标签
     *
     * @param relId    关联ID
     * @param tagType  标签类型
     * @param tagNames 标签名称集合
     */
    @Override
    @Transactional
    public void processTags(Long relId, TagTypeEnum tagType, String[] tagNames) {
        // 1. 过滤空值并去重
        Set<String> inputTags = Arrays.stream(tagNames)
            .filter(StringUtils::isNotBlank)
            .collect(Collectors.toSet());

        // 2. 批量校验存在性
        Set<String> existingTags = checkTagsExist(tagType, inputTags);

        // 3. 计算需要新增的标签
        Set<String> newTags = inputTags.stream()
            .filter(tag -> !existingTags.contains(tag))
            .collect(Collectors.toSet());

        // 4. 批量插入新标签
        if (!newTags.isEmpty()) {
            List<ExamTag> newEntities = newTags.stream()
                .map(tag -> new ExamTag()
                    .setTagType(tagType)
                    .setTagName(tag))
                .collect(Collectors.toList());
            baseMapper.insertBatch(newEntities);
        }

        // 5. 获取所有标签ID（包括新增的）
        Map<String, Long> tagIdMap = baseMapper.selectList(
            new QueryWrapper<ExamTag>()
                .select("tag_id", "tag_name")
                .eq("tag_type", tagType)
                .in("tag_name", inputTags)
        ).stream().collect(Collectors.toMap(
            ExamTag::getTagName,
            ExamTag::getTagId
        ));

        // 6. 构建关联关系
        List<ExamTagRel> relations = inputTags.stream()
            .map(tag -> new ExamTagRel()
                .setRelId(relId)
                .setTagId(tagIdMap.get(tag)))
            .collect(Collectors.toList());

        tagRelMapper.insertBatch(relations);
    }

    /**
     * 批量检查标签是否存在
     *
     * @param tagType  标签类型
     * @param tagNames 标签名称集合
     * @return 存在的标签名称集合
     */
    public Set<String> checkTagsExist(TagTypeEnum tagType, Collection<String> tagNames) {
        if (tagNames.isEmpty()) {
            return Collections.emptySet();
        }

        // 批量查询已有标签
        QueryWrapper<ExamTag> wrapper = new QueryWrapper<ExamTag>()
            .select("tag_name")
            .eq("tag_type", tagType)
            .in("tag_name", tagNames);

        return baseMapper.selectList(wrapper)
            .stream()
            .map(ExamTag::getTagName)
            .collect(Collectors.toSet());
    }

    /**
     * 将标签名称集合转换为标签ID集合
     *
     * @param tagNames 标签名称集合
     * @return 标签ID集合
     */
    @Override
    public List<Long> convertTagsToIds(String[] tagNames) {
        if (tagNames == null || tagNames.length == 0) {
            return Collections.emptyList();
        }

        return baseMapper.selectList(new QueryWrapper<ExamTag>()
                .select("tag_id")
                .in("tag_name", Arrays.asList(tagNames))
            ).stream()
            .map(ExamTag::getTagId)
            .collect(Collectors.toList());
    }
}
